package com.example.fmgidsprototype;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Typeface;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewSwitcher;

import com.example.fmgidsprototype.data.DataManager;
import com.example.fmgidsprototype.model.Category;
import com.example.fmgidsprototype.model.Venue;
import com.example.fmgidsprototype.webservice.AccountList;
import com.example.fmgidsprototype.webservice.n_cst_user_authentication;
import com.example.test.n_cst_start;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class VenuesList extends ListActivity {
	
	private List<Venue> venues;
	private List<Category> categories;
	private ProgressDialog progressDialog;
	private FmGidsPrototypeApp app;
	private DataManager dm;
	private VenuesAdapter adapter;
	private SharedPreferences prefs;
	private RelativeLayout categoryBtn;
	private TextView filterIndicator;
	private Button showMapBtn;
	private List<Venue> catVenues;
	private n_cst_user_authentication inv_user_auth;
	private String userName;
	

	private GoogleMap mMap;
	private LatLng llVenue;
	private LatLng llLastknownlocation;

	private String[] markerids = new String[150];
	private long[] markervenueid= new long[150];
	private Marker VenueMarker;
	private List<Marker> markers = new ArrayList<Marker>(); //the array is kept to find the boundries and change the view
	private LocationManager LocationManager; //system service, which provides APIs to determine location and bearing of the underlying device (if available)
	private Location lastLoc;
	public Marker MarkerMyLocation;
	public Boolean UseMyLocationForDistanceSort = false;
	public Boolean LocationPopupHasPopped = false;

	private float[] results=new float[5];
	
	int indexhelper;
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_venues_list);
		app = (FmGidsPrototypeApp)getApplication();
		venues = new ArrayList<Venue>();
		categories = new ArrayList<Category>();
		dm = app.getDataManager();
		prefs = getSharedPreferences(AppConstants.PREFS_IDENTIFIER, Context.MODE_PRIVATE);
		categoryBtn = (RelativeLayout)findViewById(R.id.bar_filterBtn);
		filterIndicator = (TextView)findViewById(R.id.bar_filterIndicator);
		showMapBtn = (Button)findViewById(R.id.toggleButton1);
		
		progressDialog = new ProgressDialog(this);
		progressDialog.setMessage("Information is been updated; please have patience.");
		progressDialog.setIndeterminate(false);
		progressDialog.setMax(100);
		progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

		long localTimeStamp = prefs.getLong(AppConstants.JSON_VENUE_DATE, 0L);
		n_cst_start start = new n_cst_start(this, dm);
		Calendar date = new GregorianCalendar(05, 01, 2012);
		start.of_get_categories_vanues(date.getTime());
		inv_user_auth = new n_cst_user_authentication(this);
		inv_user_auth.of_check_user_account();
		//in all cases, update UI
		this.updateUI();
		
		
		setUpMapIfNeeded();
		
		LocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
		
		String providerName;
		providerName = getLocationManager();
		
		// register for location updates
		LocationUpdateHandler LUH = new LocationUpdateHandler();
		LocationManager.requestLocationUpdates(providerName, 5000, 10, LUH);//provider,time,distance,listener

		/*
		 * The time it takes for your location listener to receive the first location fix is often 
		 * too long for users wait. Until a more accurate location is provided to your 
		 * location listener, you should utilize a cached location by calling getLastKnownLocation(String):
		 * */
		lastLoc = LocationManager.getLastKnownLocation(providerName);
		llLastknownlocation = new LatLng(lastLoc.getLatitude(), lastLoc.getLongitude());
		
		Float myRadius = Util.getRadiusMyDistanceFromCenter(llLastknownlocation);
		if (myRadius <= AppConstants.MaxRadiusFromCenter) {
			UseMyLocationForDistanceSort = false;

		}else{
			UseMyLocationForDistanceSort = true;
		}
		
		
		showMapBtn.setOnClickListener(new OnClickListener() {
						
			@Override
			public void onClick(View v) {
				if (showMapBtn.getText().toString().equalsIgnoreCase("Lijstweergave"))
				{
					populateMapWithMarkers();
				}
				else
				{
					// show the user the list..
					// nothing should be done at this point
				}
				
				ViewSwitcher switcher = (ViewSwitcher) findViewById(R.id.viewSwitcher);
				switcher.showNext();
			}
		});
		
        // set icon fonts
        Typeface iconFont = Typeface.createFromAsset(getAssets(), "icomoon.ttf");
        TextView filterIcon = (TextView) findViewById(R.id.bar_filter_btn_icon);
        filterIcon.setTypeface(iconFont);
		Button settingsBtn = (Button) findViewById(R.id.bar_settings_btn);
		settingsBtn.setTypeface(iconFont);
		Button infoBtn = (Button) findViewById(R.id.bar_info_btn);
		infoBtn.setTypeface(iconFont);
	}
	

	
	/**
     * Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly
     * installed) and the map has not already been instantiated.. This will ensure that we only ever
     * call {@link #setUpMap()} once when {@link #mMap} is not null.
     * <p>
     * If it isn't installed {@link SupportMapFragment} (and
     * {@link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to
     * install/update the Google Play services APK on their device.
     * <p>
     * A user can return to this FragmentActivity after following the prompt and correctly
     * installing/updating/enabling the Google Play services. Since the FragmentActivity may not have been
     * completely destroyed during this process (it is likely that it would only be stopped or
     * paused), {@link #onCreate(Bundle)} may not be called again so we should call this method in
     * {@link #onResume()} to guarantee that it will be called.
     */
	private void setUpMapIfNeeded() {
	    // Do a null check to confirm that we have not already instantiated the map.
	    if (mMap == null) {
	        mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
	        try{
	        	mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);  
	 	        mMap.setMyLocationEnabled(true);
	        }
	        catch(Exception e){
	        	e.printStackTrace();
	        }
	    }
	}
	
	private String getLocationManager(){
		Criteria provProps = new Criteria();
		provProps.setCostAllowed(false);
		provProps.setAccuracy(Criteria.ACCURACY_FINE);
		provProps.setPowerRequirement(Criteria.POWER_MEDIUM);

		// get a location provider with these criteria
		String providerName = LocationManager.getBestProvider(provProps, true);
		if (providerName == null || !LocationManager.isProviderEnabled(providerName)) {
			// if none is found use default
			providerName = LocationManager.NETWORK_PROVIDER;
		}
		
		if (!LocationManager.isProviderEnabled(providerName)) {
			String text = "No working location provider found!";
			Toast popup = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG);
			popup.show();
		}

		return providerName;
	}
	
	
	private void WrapCameraOverMarkers(){

		if (markers.size()>0)
		{
			LatLngBounds.Builder builder = new LatLngBounds.Builder();
			
			for  (Marker m : markers) {
			    builder.include(m.getPosition());
			}
			
			final LatLngBounds bounds = builder.build();
			final int padding = 10; // offset from edges of the map in pixels
			
			mMap.setOnCameraChangeListener(new OnCameraChangeListener() {
	
			    @Override
			    public void onCameraChange(CameraPosition arg0) {
			        // Move camera.
			        mMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding));
			        // Remove listener to prevent position reset on camera move.
			        mMap.setOnCameraChangeListener(null);
			    }
			});
		}
	}
	
	private class LocationUpdateHandler implements LocationListener {
		@Override
		public void onLocationChanged(Location location) {
			if (MarkerMyLocation != null){
				MarkerMyLocation.remove();
			}
			llLastknownlocation = new LatLng(location.getLatitude(), location.getLongitude());
			Util.lastLocation = llLastknownlocation;
			if(mMap != null){
				MarkerMyLocation = mMap.addMarker( new MarkerOptions().position(llLastknownlocation).title("Ik sta hier")
						.snippet("Nauwkeurig to op "+ String.format(Locale.US, "%.2f",location.getAccuracy()) + " m" ) ) ;
			}
			boolean PreviousStateDistanceSort = UseMyLocationForDistanceSort;
			float MyDistanceFromCenter = Util.getRadiusMyDistanceFromCenter(llLastknownlocation);
			
			UseMyLocationForDistanceSort = true;
			if (MyDistanceFromCenter > AppConstants.MaxRadiusFromCenter) {
				UseMyLocationForDistanceSort = false;				
			}
			
			if (PreviousStateDistanceSort != UseMyLocationForDistanceSort || LocationPopupHasPopped == false){
				String FromWhere = "";
				if (UseMyLocationForDistanceSort == true ){
					FromWhere = "uw locatie";
				}else{
					FromWhere = "de grote markt";
				}
				
				String FriendlyDistance;
				if (MyDistanceFromCenter > 1000F ){ 
					FriendlyDistance = String.format(Locale.US, "%.2f",MyDistanceFromCenter/1000) + " km";
				}else{
					FriendlyDistance = MyDistanceFromCenter + " m";
				}
				
				FromWhere = FromWhere +  " - U bevind zich op " +  FriendlyDistance ;
				
				Toast tofar = Toast.makeText(getApplicationContext(), "De afstanden worden berekend op basis van "+ FromWhere   , Toast.LENGTH_LONG);
				tofar.show();
				LocationPopupHasPopped = true;
			}
		}

		@Override
		public void onProviderDisabled(String provider) {
			// TODO Auto-generated method stub
		}

		@Override
		public void onProviderEnabled(String provider) {
			// TODO Auto-generated method stub
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			// TODO Auto-generated method stub
		}
	}
	
	private void populateMapWithMarkers(){
		Toast popup = Toast.makeText(getApplicationContext(), "De venues worden visueel aangeduid"  , Toast.LENGTH_LONG);
		popup.show();
		if(mMap == null)
			return;
		mMap.clear(); //removes all the markers, we can setup the markers based on those we have
		markers.clear();
		indexhelper = 0;
		
		for (Venue v : this.venues) { //I'm in the assumption the venues obj, gets updated in r.367 //when not commented
			llVenue = new LatLng(v.getLatitude(),v.getLongitude());			
			//calculate the distance between the venue and My Location
			Location.distanceBetween(llLastknownlocation.latitude, llLastknownlocation.longitude, v.getLatitude(), v.getLongitude(), results);
			List<Category> VenueCategory = v.getCategories(); //haal alle categories op, waar deze venue aan linkt
			
			int drawableid = R.drawable.marker_winkels;
			
			if (VenueCategory.get(0).getName().equalsIgnoreCase("bars")){
				 drawableid = R.drawable.marker_bars;
			}
			else if (VenueCategory.get(0).getName().equalsIgnoreCase("cultuur")){
				 drawableid = R.drawable.marker_cultuur;
			}
			else if (VenueCategory.get(0).getName().equalsIgnoreCase("nightlife")){
				 drawableid = R.drawable.marker_nightlife;
			}
			else if (VenueCategory.get(0).getName().equalsIgnoreCase("escapism")){
				 drawableid = R.drawable.marker_escapism;
			}
			else if (VenueCategory.get(0).getName().equalsIgnoreCase("winkels")){
				 drawableid = R.drawable.marker_winkels;
			}
			else if (VenueCategory.get(0).getName().equalsIgnoreCase("eten")){
				 drawableid = R.drawable.marker_eten;
			}
			else if (VenueCategory.get(0).getName().equalsIgnoreCase("kids")){
				 drawableid = R.drawable.marker_kids;
			}
			
			if (results[0] > 100000F){
				VenueMarker = mMap.addMarker(new MarkerOptions().position(AppConstants.LL_GREATMARKET).title(v.getName()  ).snippet("Klik voor detail "/* + VenueCategory.get(0).getName() *//*+ " afstand: " + String.format(Locale.US, "%.2f",results[0]/1000) + " km"*/).icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_outofrange)));
			}else{
				VenueMarker = mMap.addMarker(new MarkerOptions().position(llVenue).title(v.getName()  ).snippet("Klik voor detail "/* + VenueCategory.get(0).getName() *//*+ " afstand: " + String.format(Locale.US, "%.2f",results[0]/1000) + " km"*/).icon(BitmapDescriptorFactory.fromResource(drawableid)));
			}
			markerids[indexhelper] = VenueMarker.getId();
			markervenueid[indexhelper] = v.getId();
			
			indexhelper = indexhelper + 1;
			markers.add(VenueMarker);
		}

		MarkerMyLocation = mMap.addMarker( new MarkerOptions().position(llLastknownlocation).title("Found you").snippet("Nauwkeurig to op "+ String.format(Locale.US, "%.2f",lastLoc.getAccuracy()) + " m" ).icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_youarehere)) ) ;
		markers.add(MarkerMyLocation);

		
		//markers met id's mappen...
		mMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
			
			@Override
			public void onInfoWindowClick(Marker marker) {
				
				int size = markerids.length;
			    for (int i=0; i<size; i++)
			    {
			    	
			    	if (marker.getId().equalsIgnoreCase(markerids[i])){
			    		
			    		// redundante code, deze wordt ook gebruikt in onListItemClick
			    		// variable i komt overeen met de index van de array
			    		// komt "toevallig" ook overeen met de adapter index
			    		app.setCategoryVenues(catVenues);
			    		app.setCurrentVenue(i);
			    		Venue selectedVenue = adapter.getItem(i);
			    		Toast.makeText(getApplicationContext(), selectedVenue.getName(), Toast.LENGTH_LONG).show();
			
			    		Intent intent = new Intent(getApplicationContext(), DetailSliderActivity.class);
						intent.putExtra(AppConstants.SELECTED_VENUE, selectedVenue );
						startActivity(intent);
			    	}
			    }	
			}
		});
		WrapCameraOverMarkers();
	}
	
	private void updateUI(){
		new VenueDownloader().execute();
	}
	
	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		app.setCategoryVenues(catVenues);
		app.setCurrentVenue(position);
		Venue selectedVenue = adapter.getItem(position);
		Intent intent = new Intent(getApplicationContext(), DetailSliderActivity.class);
		intent.putExtra(AppConstants.SELECTED_VENUE, selectedVenue);
		startActivity(intent);
		super.onListItemClick(l, v, position, id);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_venues_list, menu);
		return true;
	}
	
	
	public void updateTimeStamp(long timeStamp, String resourceName){
		Editor editor = prefs.edit();
		editor.remove(resourceName);
		editor.putLong(resourceName, timeStamp);
		editor.commit();
	}
	
	private final List<Venue> sort(List<Venue> input){
		//sort venues by distance from zero
		Collections.sort(input, new Comparator<Venue>(){
			//TODO: implement this with Bart's Famous Distance Calculation Method 
			//for now this uses hard coded distance from Point Zero
			public int compare(Venue v1, Venue v2){	
				
				if (UseMyLocationForDistanceSort == true){
					float[] distancev1 =new float[5];
					Location.distanceBetween(v1.getLatitude(), v1.getLongitude(), llLastknownlocation.latitude, llLastknownlocation.longitude, distancev1 );
					float[] distancev2 =new float[5];
					Location.distanceBetween(v2.getLatitude(), v2.getLongitude(), llLastknownlocation.latitude, llLastknownlocation.longitude, distancev2 );
					
					return (distancev1[0] <= distancev2[0]) ? -1 : 1;
				}else
				{
					return (v1.getDistanceFromZero() <= v2.getDistanceFromZero()) ? -1 : 1;
				}
				
			}
		});
		return input;
	}
	
	private List<Venue> copy(List<Venue> list){
		List<Venue> copyList = new ArrayList<Venue>();
		for(Venue v : list){
			copyList.add(v);
		}
		return copyList;
	}
	
	private class VenueDownloader extends AsyncTask<Void, Integer, Void>{
		
		@Override
		protected void onPostExecute(Void result) {
			app.setVenues(venues);
			app.setAllCategories(categories);
			final HashMap<String, Long> catMap = new HashMap<String, Long>();
			List<String> catNames = new ArrayList<String>();
			catNames.add("All Venues");
			for(Category c : categories){
				catNames.add(c.getName());
				catMap.put(c.getName(), c.getId());
			}
			ListView listView = getListView();
			adapter = new VenuesAdapter(VenuesList.this, venues, llLastknownlocation);
			listView.setAdapter(adapter);
			ImageView catIcon = (ImageView)findViewById(R.id.catlist_img);
			
			final CatsAdapter catsAdapter = new CatsAdapter(
					getApplicationContext(), catNames);
			categoryBtn.setOnClickListener(new OnClickListener() {	
				@Override
				public void onClick(View v) {
					new AlertDialog.Builder(VenuesList.this, R.style.DialogFmb).setAdapter(catsAdapter, 
							new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									String selected = catsAdapter.getItem(which);
									if(!selected.equals("All Venues")){
										long catId = catMap.get(selected);
										catVenues = VenuesList.this.sort(dm.getAllVenuesForCategory(catId));
										filterIndicator.setText(selected);
									}
									else{
										catVenues = VenuesList.this.sort(dm.getAllVenuesWithLocations());
										filterIndicator.setText("");
									}
									app.setSelectedCategoryName(selected);
									adapter.clear();
									adapter.addAll(catVenues);
									adapter.notifyDataSetChanged();

									populateMapWithMarkers();
									app.setCategoryVenues(catVenues);
									dialog.dismiss();
								}
					}).create().show();
				}
			});
			super.onPostExecute(result);
		}

		@Override
		protected Void doInBackground(Void... params) {
			venues = VenuesList.this.sort(dm.getAllVenuesWithLocations());
			catVenues = new ArrayList<Venue>();
			catVenues = VenuesList.this.copy(venues);
			categories = dm.getAllCategories();
			return null;
		}
		
	}
	
	protected void onActivityResult(int requestCode, int resultCode, Intent data){
		if (requestCode == AccountList.REQUEST_CODE && resultCode == Activity.RESULT_OK){
			
			// A contact was picked. Here we will just display it to the user.
			if (data.hasExtra(AccountList.RETURN_EMAIL)){
				inv_user_auth.of_set_email(data.getExtras().getString(AccountList.RETURN_EMAIL));
			}
		}
	}
	
}
